#ifndef SemanticDataCollector_h
#define SemanticDataCollector_h

#include "simodo/interpret/SemanticDataCollector_interface.h"

#include <vector>

class SemanticDataCollector final : public simodo::interpret::SemanticDataCollector_interface
{
    using Tokens = std::vector<simodo::inout::Token>;
    using Declared = std::vector<simodo::variable::Variable>;
    using Used = std::vector<std::pair<simodo::variable::Variable, simodo::inout::TokenLocation>>;
    using Scoped = std::vector<std::pair<simodo::inout::TokenLocation, simodo::inout::TokenLocation>>;
    using Refs = std::vector<std::pair<simodo::inout::Token, std::u16string>>;
    using Remotes = std::vector<simodo::inout::TokenLocation>;

    Tokens   _tokens;
    Declared _declared;
    Used     _used;
    Scoped   _scoped;
    Refs     _refs;
    Remotes  _remotes;

public:
    SemanticDataCollector()
    {
        _tokens.reserve(1024);
        _declared.reserve(1024);
        _used.reserve(1024);
        _scoped.reserve(1024);
        _refs.reserve(1024);
        _remotes.reserve(1024);
    }

    void swap(SemanticDataCollector & other) noexcept {
        other._tokens.swap(_tokens);
        other._declared.swap(_declared);
        other._used.swap(_used);
        other._scoped.swap(_scoped);
        other._refs.swap(_refs);
        other._remotes.swap(_remotes);
    }

    const Tokens &   tokens()   const { return _tokens; }
    const Declared & declared() const { return _declared; }
    const Used &     used()     const { return _used; }
    const Scoped &   scoped()   const { return _scoped; }
    const Refs &     refs()     const { return _refs; }
    const Remotes &  remotes()  const { return _remotes; }

    virtual void collectToken(const simodo::inout::Token & t) override
    {
        _tokens.push_back(t);
    }
    virtual void collectNameDeclared(const simodo::variable::Variable & var) override
    {
        _declared.push_back(var);
    }
    virtual void collectNameInitiated(const simodo::variable::Variable & ) override;
    virtual void collectNameAssigned(const simodo::variable::Variable & , const simodo::inout::TokenLocation & ) override {}
    virtual void collectNameUsed(const simodo::variable::Variable & var, const simodo::inout::TokenLocation & used_location) override
    {
        _used.emplace_back(var, used_location);
    }
    virtual void collectScoped(const simodo::inout::TokenLocation & begin, const simodo::inout::TokenLocation & end) override
    {
        _scoped.emplace_back(begin, end);
    }
    virtual void collectRef(const simodo::inout::Token & token, const std::u16string & ref) override
    {
        _refs.emplace_back(token, ref);
    }
    virtual void collectRemoteFunctionLaunch(const simodo::inout::TokenLocation & location) override 
    {
        _remotes.emplace_back(location);
    }
};

#endif
